home *** CD-ROM | disk | FTP | other *** search
/ Chip: Internet / Chip Internet.iso / viewer / sox7dos / smp.c < prev    next >
Text File  |  1993-02-11  |  8KB  |  305 lines

  1. /*
  2.  * June 30, 1992
  3.  * Copyright 1992 Leigh Smith And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Leigh Smith And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools SampleVision file format driver.
  12.  * Output is always in little-endian (80x86/VAX) order.
  13.  * 
  14.  * Derived from: Sound Tools skeleton handler file.
  15.  */
  16.  
  17. #include "st.h"
  18. #include <string.h>
  19.  
  20. #define NAMELEN    30        /* Size of Samplevision name */
  21. #define COMMENTLEN 60        /* Size of Samplevision comment, not shared */
  22. #define MIDI_UNITY 60        /* MIDI note number to play sample at unity */
  23.  
  24. /* The header preceeding the sample data */
  25. struct smpheader {
  26.     char Id[18];        /* File identifier */
  27.     char version[4];    /* File version */
  28.     char comments[COMMENTLEN];    /* User comments */
  29.     char name[NAMELEN + 1];    /* Sample Name, left justified */
  30. };
  31. #define HEADERSIZE (sizeof(struct smpheader) - 1)    /* -1 for name's \0 */
  32.  
  33. /* Samplevision loop definition structure */
  34. struct loop {
  35.     unsigned long start; /* Sample count into sample data, not byte count */
  36.     unsigned long end;   /* end point */
  37.     char type;         /* 0 = loop off, 1 = forward, 2 = forw/back */
  38.     short count;         /* No of times to loop */
  39. };
  40.  
  41. /* Samplevision marker definition structure */
  42. struct marker {
  43.     char name[10];        /* Ascii Marker name */
  44.     unsigned long position;    /* Sample Number, not byte number */
  45. };
  46.  
  47. /* The trailer following the sample data */
  48. struct smptrailer {
  49.     struct loop loops[8];        /* loops */
  50.     struct marker markers[8];    /* markers */
  51.     char MIDInote;            /* for unity pitch playback */
  52.     unsigned long rate;        /* in hertz */
  53.     unsigned long SMPTEoffset;    /* in subframes */
  54.     unsigned long CycleSize;    /* sample count in one cycle of the */
  55.                     /* sampled sound -1 if unknown */
  56. };
  57.  
  58. /* Private data for SMP file */
  59. typedef struct smpstuff {
  60.     unsigned long NoOfSamps;    /* Sample data count in words */
  61.     char comment[NAMELEN + 1];    /* comment memory resides in private */
  62. } *smp_t;                /* data because it's small */
  63.  
  64. char *SVmagic = "SOUND SAMPLE DATA ", *SVvers = "2.1 ";
  65.  
  66. IMPORT float volume, amplitude;
  67. IMPORT int summary, verbose;
  68.  
  69. /*
  70.  * Read the SampleVision trailer structure.
  71.  * Returns 1 if everything was read ok, 0 if there was an error.
  72.  */
  73. static int readtrailer(ft, trailer)
  74. ft_t ft;
  75. struct smptrailer *trailer;
  76. {
  77.     int i;
  78.  
  79.     rlshort(ft);            /* read reserved word */
  80.     for(i = 0; i < 8; i++) {    /* read the 8 loops */
  81.         trailer->loops[i].start = rllong(ft);
  82.         trailer->loops[i].end = rllong(ft);
  83.         trailer->loops[i].type = getc(ft->fp);
  84.         trailer->loops[i].count = rlshort(ft);
  85.     }
  86.     for(i = 0; i < 8; i++) {    /* read the 8 markers */
  87.         if (fread(trailer->markers[i].name, 1, 10, ft->fp) != 10)
  88.             return(0);
  89.         trailer->markers[i].position = rllong(ft);
  90.     }
  91.     trailer->MIDInote = getc(ft->fp);
  92.     trailer->rate = rllong(ft);
  93.     trailer->SMPTEoffset = rllong(ft);
  94.     trailer->CycleSize = rllong(ft);
  95.     return(1);
  96. }
  97.  
  98. /*
  99.  * set the trailer data - loops and markers, to reasonably benign values
  100.  */
  101. static settrailer(trailer, rate)
  102. struct smptrailer *trailer;
  103. unsigned int rate;
  104. {
  105.     int i;
  106.  
  107.     trailer->loops[0].start = ~0;    /* set first loop start as FFFFFFFF */
  108.     trailer->loops[0].end = 0;    /* to mark it as not set */
  109.     trailer->loops[0].type = 0;
  110.     trailer->loops[0].count = 0;
  111.     for(i = 1; i < 8; i++) {    /* assign the 7 other loops */
  112.         trailer->loops[i].start = 0;
  113.         trailer->loops[i].end = 0;
  114.         trailer->loops[i].type = 0;
  115.         trailer->loops[i].count = 0;
  116.     }
  117.     for(i = 0; i < 8; i++) {    /* write the 8 markers */
  118.         strcpy(trailer->markers[i].name, "          ");
  119.         trailer->markers[i].position = ~0;
  120.     }
  121.     trailer->MIDInote = MIDI_UNITY;        /* Unity play back */
  122.     trailer->rate = rate;
  123.     trailer->SMPTEoffset = 0;
  124.     trailer->CycleSize = -1;
  125. }
  126.  
  127. /*
  128.  * Write the SampleVision trailer structure.
  129.  * Returns 1 if everything was written ok, 0 if there was an error.
  130.  */
  131. static int writetrailer(ft, trailer)
  132. ft_t ft;
  133. struct smptrailer *trailer;
  134. {
  135.     int i;
  136.  
  137.     wlshort(ft, 0);            /* write the reserved word */
  138.     for(i = 0; i < 8; i++) {    /* write the 8 loops */
  139.         wllong(ft, trailer->loops[i].start);
  140.         wllong(ft, trailer->loops[i].end);
  141.         putc(trailer->loops[i].type, ft->fp);
  142.         wlshort(ft, trailer->loops[i].count);
  143.     }
  144.     for(i = 0; i < 8; i++) {    /* write the 8 markers */
  145.         if (fwrite(trailer->markers[i].name, 1, 10, ft->fp) != 10)
  146.             return(0);
  147.         wllong(ft, trailer->markers[i].position);
  148.     }
  149.     putc(trailer->MIDInote, ft->fp);
  150.     wllong(ft, trailer->rate);
  151.     wllong(ft, trailer->SMPTEoffset);
  152.     wllong(ft, trailer->CycleSize);
  153.     return(1);
  154. }
  155.  
  156. /*
  157.  * Do anything required before you start reading samples.
  158.  * Read file header. 
  159.  *    Find out sampling rate, 
  160.  *    size and style of samples, 
  161.  *    mono/stereo/quad.
  162.  */
  163. smpstartread(ft) 
  164. ft_t ft;
  165. {
  166.     smp_t smp = (smp_t) ft->priv;
  167.     int littlendian = 0, i;
  168.     long samplestart;
  169.     char *endptr;
  170.     struct smpheader header;
  171.     struct smptrailer trailer;
  172.  
  173.     /* If you need to seek around the input file. */
  174.     if (! ft->seekable)
  175.         fail("SMP input file must be a file, not a pipe");
  176.  
  177.     /* Read SampleVision header */
  178.     if (fread((char *) &header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
  179.         fail("unexpected EOF in SMP header");
  180.     if (strncmp(header.Id, SVmagic, 17) != 0)
  181.         fail("SMP header does not begin with magic word %s\n", SVmagic);
  182.     if (strncmp(header.version, SVvers, 4) != 0)
  183.         fail("SMP header is not version %s\n", SVvers);
  184.  
  185.     strncpy(smp->comment, header.name, NAMELEN);
  186.         for (i = NAMELEN; i >= 0 && smp->comment[i] == ' '; i--)
  187.         smp->comment[i] = '\0';
  188.     ft->comment = smp->comment;
  189.     report("SampleVision File name: %s", ft->comment);
  190.     report("File comments: %.*s", COMMENTLEN, header.comments);
  191.     /* Extract out the sample size (always intel format) */
  192.     smp->NoOfSamps = rllong(ft);
  193.     /* mark the start of the sample data */
  194.     samplestart = ftell(ft->fp);
  195.  
  196.     /* seek from the current position (the start of sample data) by */
  197.     /* NoOfSamps * 2 */
  198.     if (fseek(ft->fp, smp->NoOfSamps * 2L, 1) == -1)
  199.         fail("SMP unable to seek to trailer");
  200.     if (!readtrailer(ft, &trailer))
  201.         fail("unexpected EOF in SMP trailer");
  202.  
  203.     /* seek back to the beginning of the data */
  204.     if (fseek(ft->fp, samplestart, 0) == -1) 
  205.         fail("SMP unable to seek back to start of sample data");
  206.  
  207.     ft->info.rate = (int) trailer.rate;
  208.     ft->info.size = WORD;
  209.     ft->info.style = SIGN2;
  210.     ft->info.channels = 1;
  211.  
  212.     endptr = (char *) &littlendian;
  213.     *endptr = 1;
  214.     if (littlendian != 1)
  215.         ft->swap = 1;
  216. }
  217.  
  218. /*
  219.  * Read up to len samples from file.
  220.  * Convert to signed longs.
  221.  * Place in buf[].
  222.  * Return number of samples read.
  223.  */
  224. smpread(ft, buf, len) 
  225. ft_t ft;
  226. long *buf, len;
  227. {
  228.     smp_t smp = (smp_t) ft->priv;
  229.     register long datum;
  230.     int done = 0;
  231.     
  232.     for(; done < len && smp->NoOfSamps; done++, smp->NoOfSamps--) {
  233.         datum = rshort(ft);
  234.         /* scale signed up to long's range */
  235.         *buf++ = LEFT(datum, 16);
  236.     }
  237.     return done;
  238. }
  239.  
  240. /*
  241.  * Do anything required when you stop reading samples.  
  242.  * Don't close input file! 
  243.  */
  244. smpstopread(ft) 
  245. ft_t ft;
  246. {
  247. }
  248.  
  249. smpstartwrite(ft) 
  250. ft_t ft;
  251. {
  252.     smp_t smp = (smp_t) ft->priv;
  253.     struct smpheader header;
  254.  
  255.     /* If you have to seek around the output file */
  256.     if (! ft->seekable)
  257.         fail("Output .smp file must be a file, not a pipe");
  258.  
  259.     /* If your format specifies any of the following info. */
  260.     ft->info.size = WORD;
  261.     ft->info.style = SIGN2;
  262.     ft->info.channels = 1;
  263.  
  264.     strcpy(header.Id, SVmagic);
  265.     strcpy(header.version, SVvers);
  266.     sprintf(header.comments, "%-*s", COMMENTLEN, "Converted using Sox.");
  267.     sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, ft->comment);
  268.  
  269.     /* Write file header */
  270.     if(fwrite(&header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
  271.         fail("SMP: Can't write header completely");
  272.     wllong(ft, 0);    /* write as zero length for now, update later */
  273.     smp->NoOfSamps = 0;
  274. }
  275.  
  276. smpwrite(ft, buf, len) 
  277. ft_t ft;
  278. long *buf, len;
  279. {
  280.     smp_t smp = (smp_t) ft->priv;
  281.     register int datum;
  282.  
  283.     while(len--) {
  284.         datum = RIGHT(*buf++, 16);
  285.         wlshort(ft, datum);
  286.         smp->NoOfSamps++;
  287.     }
  288.     /* If you cannot write out all of the supplied samples, */
  289.     /*    fail("SMP: Can't write all samples to %s", ft->filename); */
  290. }
  291.  
  292. smpstopwrite(ft) 
  293. ft_t ft;
  294. {
  295.     smp_t smp = (smp_t) ft->priv;
  296.     struct smptrailer trailer;
  297.  
  298.     /* Assign the trailer data */
  299.     settrailer(&trailer, ft->info.rate);
  300.     writetrailer(ft, &trailer);
  301.     if (fseek(ft->fp, 112, 0) == -1)
  302.         fail("SMP unable to seek back to save size");
  303.     wllong(ft, smp->NoOfSamps);
  304. }
  305.